package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.user.*;
import com.atguigu.tingshu.user.factory.impl.StrategyFactoryImpl;
import com.atguigu.tingshu.user.mapper.*;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.user.strategy.ItemTypeStrategy;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.util.Asserts;
import org.joda.time.LocalDateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private WxMaService wxMaService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;
    @Autowired
    private UserPaidTrackMapper userPaidTrackMapper;
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;
    @Autowired
    private VipServiceConfigMapper vipServiceConfigMapper;
    @Autowired
    private UserVipServiceMapper userVipServiceMapper;

    @Autowired
    private StrategyFactoryImpl strategyFactoryImpl;

    @SneakyThrows
    @Override
    public Map<String, Object> wxLogin(String code) {
        //	调用服务方法 获取openId
        WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.jsCode2SessionInfo(code);
        //	获取openid;
        String openid = wxMaJscode2SessionResult.getOpenid();
        //	使用 openid 查询数据库，判断用户是否已经注册
        UserInfo userInfo = this.getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getWxOpenId, openid));
        //	判断
        if (null == userInfo) {
            //	当前没有注册过;
            userInfo = new UserInfo();
            userInfo.setWxOpenId(openid);
            userInfo.setNickname("听友" + System.currentTimeMillis());
            userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
            //	保存数据
            this.save(userInfo);
            //  初始化账户信息
            rabbitService.sendMessage(MqConst.EXCHANGE_USER, MqConst.ROUTING_USER_REGISTER, userInfo.getId());
        }
        //	直接返回登录成功！
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        //  组成缓存key
        String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
        this.redisTemplate.opsForValue().set(userLoginKey, userInfo, RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);
        //	创建返回的Map 集合
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        return map;
    }

    /**
     * 根据用户id 查询用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public UserInfoVo getUserInfo(Long userId) {

        UserInfo userInfo = this.getById(userId);

        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, userInfoVo);

        return userInfoVo;
    }

    /**
     * 修改用户信息
     *
     * @param userId
     * @param userInfoVo
     */

    @Override
    public void updateUserInfo(Long userId, UserInfoVo userInfoVo) {
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(userInfoVo, userInfo);

        userInfo.setId(userId);
        this.updateById(userInfo);
    }

    /**
     * 查询用户是否购买了该专辑的指定付费的音频
     *
     * @param userId
     * @param albumId
     * @param trackNeedPaidIdList
     * @return
     */
    @Override
    public Map<Long, Integer> getUserIsPaidTrack(Long userId, Long albumId, List<Long> trackNeedPaidIdList) {
        //	先判断当前这个用户是否购买过专辑; user_paid_album  根据UserId,albumId 获取到用户付款专辑对象
        UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getAlbumId, albumId).eq(UserPaidAlbum::getUserId, userId));
        //	判断对象是否为空
        if (null != userPaidAlbum) {
            //	说明这个用户购买过专辑,需要将需要购买的声音Id 设置为免费; trackId:1;  如果查询到对应的专辑购买记录，则默认将声音Id 赋值为 1
            return trackNeedPaidIdList.stream().collect(Collectors.toMap(trackNeedPaidId -> trackNeedPaidId, trackNeedPaidId -> 1));
        }
        //	当前这个用户没有购买专辑, 查看是否购买过声音; user_paid_track
        //	查询当前这个用户，是否购买过当前专辑中需要付费的声音列表： select * from user_paid_track where user_id = 28 and album_id = 1429 and track_id in ( 48241,48249);
        List<UserPaidTrack> userPaidTracks = userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getAlbumId, albumId).eq(UserPaidTrack::getUserId, userId));
        //	获取到用户购买声音Id 集合
        List<Long> paidTrackIdList = userPaidTracks.stream().map(userPaidTrack -> userPaidTrack.getTrackId()).collect(Collectors.toList());
        //	创建一个map 集合
        HashMap<Long, Integer> UserIsPaidTrackMap = new HashMap<>();
        //	trackNeedPaidIdList -- 需要所有付费的声音Id;  paidTrackIdList 不需要付费的声音Id;
        for (Long trackNeedPaidId : trackNeedPaidIdList) {
            //	判断trackIdPaidList 集合中是否包含指定的元素trackNeedPaidId  如果trackIdPaidList 集合中存在该元素trackNeedPaidId ，则返回 true；否则返回 false。
            if (paidTrackIdList.contains(trackNeedPaidId)) {
                //	设置免费 不需要付费
                UserIsPaidTrackMap.put(trackNeedPaidId, 1);
            } else {
                //  设置付费  需要付费
                UserIsPaidTrackMap.put(trackNeedPaidId, 0);
            }
        }
        //返回UserIsPaidTrackMap 结果集
        return UserIsPaidTrackMap;
    }

    /**
     * 判断用户是否购买了专辑
     *
     * @param userId
     * @param albumId
     * @return
     */
    @Override
    public boolean isPaidAlbum(Long userId, Long albumId) {
        return userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getAlbumId, albumId).eq(UserPaidAlbum::getUserId, userId)) != null;
    }

    /**
     * 根据专辑id获取用户支付过的声音id列表
     *
     * @param userId
     * @param albumId
     * @return
     */
    @Override
    public List<Long> findUserPaidTrackList(Long userId, Long albumId) {

        List<UserPaidTrack> userPaidTrack = userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getUserId, userId).eq(UserPaidTrack::getAlbumId, albumId));

        List<Long> userPaidTrackIdList = userPaidTrack.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());

        return userPaidTrackIdList;
    }

    /**
     * 处理用户购买记录 保存用户购买交易记录; user_paid_album user_paid_track user_vip_service
     *
     * @param userPaidRecordVo
     */
    @Override
    public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) {
        //根据类型调用不同的接口方法 //从策略工厂中获取对应的策略对象
        ItemTypeStrategy itemTypeStrategy = strategyFactoryImpl.writePaiRecode(userPaidRecordVo.getItemType());
        //执行策略对象的任务
        itemTypeStrategy.savePaidRecord(userPaidRecordVo);
/**
        //  本质就是保存数据：user_paid_album user_paid_track user_vip_service
        //订单付款项目类型 1001-专辑 1002-声音 1003-vip会员
        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(userPaidRecordVo.getItemType())) { //1001 专辑
            //  先查询是否有购买记录;
            boolean falg = this.isPaidAlbum(userPaidRecordVo.getUserId(), userPaidRecordVo.getItemIdList().get(0));
            if (falg) return;
            UserPaidAlbum userPaidAlbum = new UserPaidAlbum();
            userPaidAlbum.setOrderNo(userPaidRecordVo.getOrderNo());
            userPaidAlbum.setUserId(userPaidRecordVo.getUserId());
            //  专辑Id 声音Id vip_service_config.id ==> order_detial.item_id;
            userPaidAlbum.setAlbumId(userPaidRecordVo.getItemIdList().get(0));
            //  添加购买专辑信息;
            userPaidAlbumMapper.insert(userPaidAlbum);
        } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(userPaidRecordVo.getItemType())) { // ORDER_ITEM_TYPE_TRACK="1002";  // 声音
            //添加购买声音 如果只有小程序--单线程的。不会出现脏数据，如果有多个平台；pc,h5
            //通过用户id、专辑id 查询到已购买的集合；判断已购买的集合中是否包含trackId; 如果包含，不能执行插入。使用continue 跳出当前循环 并可能退还对应的金额
            //1、通过用户支付声音userPaidTrackMapper接口 通过用户id 订单号 判断该订单是否有订单支付count记录
            LambdaQueryWrapper<UserPaidTrack> wrapper = new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getUserId, userPaidRecordVo.getUserId()).eq(UserPaidTrack::getOrderNo, userPaidRecordVo.getOrderNo());
            Long count = userPaidTrackMapper.selectCount(wrapper);
            //有订单数count 直接return结束
            if (count > 0) return;
            //从形参vo中拿取订单的声音id list
            List<Long> itemIdList = userPaidRecordVo.getItemIdList();
            //通过声音远程接口，根据声音id 查询声音信息 获取专辑id 赋值结果集
            Result<TrackInfo> trackInfoResult = trackInfoFeignClient.getTrackInfoById(itemIdList.get(0));
            Asserts.notNull(trackInfoResult, "声音信息不存在");
            TrackInfo trackInfo = trackInfoResult.getData();
            Asserts.notNull(trackInfo, "声音信息不存在");
            //遍历订单itemIdList  声音idList 创建UserPaidTrack对象 依次保存到UserPaidTrack表
            for (Long itemId : itemIdList) {
                UserPaidTrack userPaidTrack = new UserPaidTrack();
                userPaidTrack.setOrderNo(userPaidRecordVo.getOrderNo());
                userPaidTrack.setUserId(userPaidRecordVo.getUserId());
                userPaidTrack.setAlbumId(trackInfo.getAlbumId());
                userPaidTrack.setTrackId(itemId);
                userPaidTrackMapper.insert(userPaidTrack);
            }
        } else {// vip会员
            //  vip:user_vip_service 用户VIP服务记录表： userInfo.setIsVip(1);
            //先获取到用户购买vip的哪种套餐 1,3,12 月；
            List<Long> itemIdList = userPaidRecordVo.getItemIdList();
            //远程调用vipServiceConfigMapper,根据套餐id获取套餐信息 vipServiceConfig
            VipServiceConfig vipServiceConfig = vipServiceConfigMapper.selectById(itemIdList.get(0));
            //  获取购买的月数
            Integer serviceMonth = vipServiceConfig.getServiceMonth();
            //定义当前系统时间 作为用户vip开始时间计算 currentTime 默认非续期 vip开始日期为当前日期
            Date currentTime = new Date();
            //  分情况：是否属于续期情况（当前这个用户属于vip也没有过期）
            //调用本模块userInfoMapper，查询用户信息
            UserInfo userInfo = userInfoMapper.selectById(userPaidRecordVo.getUserId());
            // 判断用户信息是否是vip、vip是否过期，判断是否是续期：
            if (1 == userInfo.getIsVip().intValue() && userInfo.getVipExpireTime().after(new Date())) {
                //续期，当前系统时间 即用户vip开始时间计算 为用户VIP结束时间vip_expire_time
                currentTime=userInfo.getVipExpireTime();
            }
            //计算vip结束日期expireTime  LocalDate LocalDateTime LocalTime-->LocalDateTime().plusMonths().toDate
            Date expireTime = new LocalDateTime(currentTime).plusMonths(serviceMonth).toDate();
            //  创建UserVipService对象 保存vip:user_vip_service 用户VIP服务记录表：
            UserVipService userVipService = new UserVipService();
            userVipService.setOrderNo(userPaidRecordVo.getOrderNo());
            userVipService.setUserId(userPaidRecordVo.getUserId());
            userVipService.setStartTime(currentTime);
            userVipService.setExpireTime(expireTime);
            userVipServiceMapper.insert(userVipService);

//            //排除异常 测试Seata 分布式事务
//            int i=1/0;

            //修改远程调用返回的userinfo信息 IsVip(1); VipExpireTime(expireTime);
            userInfo.setIsVip(1);
            userInfo.setVipExpireTime(expireTime);
            userInfoMapper.updateById(userInfo);

        }
*/
    }
}






















